热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

次序|更多_AspectJ——切入点语法之thistargetargsif以及逻辑运算

篇首语:本文由编程笔记#小编为大家整理,主要介绍了AspectJ——切入点语法之thistargetargsif以及逻辑运算相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了AspectJ——切入点语法之thistargetargsif以及逻辑运算相关的知识,希望对你有一定的参考价值。



更多的切入点语法

本节介绍AspectJ中更多的切入点语法,有很多在之前都用过,这里做一个总结。


0.捕获this引用的是特定类型对象的连接点

AspectJ提供了this原生切入点来捕获所有的连接点,这些连接点处的this引用的是一个特定的类型。

我们在Test13包下做测试,首先业务类Service如下:

package Test13;
public class Service
public int add(int a, int b)
return a + b;

public double square(double a)
return a * a;

public String upper(String string)
return string.toUpperCase();

其包含三个方法。测试类Main如下:

package Test13;
public class Main
public static void main(String[] args)
Service service = new Service();
System.out.println("service.add(1, 2) = " + service.add(1, 2));
System.out.println("service.square(6) = " + service.square(6));
System.out.println("service.upper(\\"Gavin\\") = " + service.upper("Gavin"));

接着我们定义切面ThisAspect,如下:

package Test13;
public aspect ThisAspect
pointcut thisPointcut(Service service): this(service);
before(Service service): thisPointcut(service)
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(service);

切面中,我们定义了thisPointcut(Service service)切入点,该切入点使用this(service)选择在源代码中this引用的是一个Service对象的连接点。在这里例子中,其实也就是所有在Service类中的连接点。运行结果如下:

通常情况下,this原生切入点和其他切入点配合使用,使在通知中可以使用当前this引用的对象。


1.使用target捕获目标对象是特定类型的连接点

this原生切入点类似,target原生切入点可以捕获所有目标对象是特定类型连接点。如在上例中,我们将切入点的this变成target:

package Test13;
public aspect ThisAspect
pointcut thisPointcut(Service service): target(service);
before(Service service): thisPointcut(service)
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println(service);

此时,就会捕获所有目标对象是Service类对象的连接点,运行结果如下:

可以看到,多出来了Main类中的几个对Service类方法的调用连接点,因为这些连接点的目标对象是Service类的对象,所以都被捕获到。而其他的原本就在Service类中的连接点也依然被捕获到,它们的目标对象显然也是Service类对象。

target原生切入点通常也与其他切入点结合使用。


2.使用args捕获具有特定参数类型、参数次序和参数个数的连接点

使用args可以捕获具有特定参数类型、参数次序、参数个数的连接点。在args中也可以使用通配符,用以选择通配符指定的具有特定参数个数和次序的连接点。

我们在Test14包下做测试,业务类Service和测试类Main与上例一样,另外我们新建切面ArgsAspect,如下:

package Test14;
public aspect ArgsAspect
pointcut argsPointcut(): args(*, *);
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

我们使用args(*, *)选择具有两个参数的连接点。运行结果如下:

如果我们将args(*, *)换成args(*),那么就只会选择只有一个参数的通配符了:

package Test14;
public aspect ArgsAspect
pointcut argsPointcut(): args(*) && !within(ArgsAspect);
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

另外,还可以使用args(*, int),选择有两个参数,并且第二个参数是int类型的连接点;args(float, .., int)选择第一个参数是float类型,最后一个参数是int类型的,并且中间有任意个参数的连接点。

通常情况下,args通常和其他切入点一起使用,来获取连接点的参数,如下用法:

package Test14;
public aspect ArgsAspect
pointcut argsPointcut(int a, int b): call(* add(..)) && args(a, b);
before(int a, int b): argsPointcut(a, b)
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());
System.out.println("第一个参数是:" + a);
System.out.println("第二个参数是:" + b);

运行结果是:


3.切入点的与或非运算

切入点之间可以进行与或非运算,分别对应符号&&||!

&&表示同时满足多个切入点表达式的切入点。关于&&的示例前面见过很多,这里不再赘述。

||的意义也很明显,它可以让切入点选择多个不同的连接点。比如,我们将上面的例子修改如下:

public aspect ArgsAspect
pointcut argsPointcut(): call(* add(..)) || call(* square(..));
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

call(* add(..)) || call(* square(..))表示捕获对add方法的调用和对square方法的调用,运行结果如下:

!运算前面也用到过,其作用是取反,比如!withincode(* add(..))排除在add方法中的连接点,!within(ArgsAspect)排除在切面ArgsAspect中的连接点。另外,非运算也可以用在某一个方法签名的字段前面, 比如我们继续将上例修改如下:

public aspect ArgsAspect
pointcut argsPointcut(): execution(public !static * *(..));
before(): argsPointcut()
System.out.println(thisJoinPoint);
System.out.println(thisJoinPoint.getSourceLocation());

切入点execution(public !static * *(..))表示所有非静态方法的执行连接点,也就是捕获除了public static void main(String[] args)方法之外的其他所有方法的执行连接点,运行结果如下:

如果将!static改为static,那么此时的运行结果为:

两者的区别显而易见。


4.使用if来设置连接点上的运行时条件

if原生切入点可以设置运行时条件,只有在if判断为true的时候,才捕获该连接点。语法是:

pointcut [切入点名字](要获取的参数): if(Boolean expression);

其具有两个关键特征:


  1. if(Boolean expression)切入点评估在运行时提供的变量,得到关于连接点是否应该触发相应通知的truefalse结果。
  2. expression可以由多个逻辑元素组成,包括展示的连接点环境、静态变量、以及其他切入点声明。

我们在Test15包下做一个简单的测试(这个测试可能不太符合常理,不过演示出效果即可),首先新建People类:

package Test15;
public class People
private String name;
private int age;
public People(String name, int age)
this.name = name;
this.age = age;

public String getName()
return name;

public void setName(String name)
this.name = name;

public void drive()
System.out.println(name + "不可以开车...");

其中它有属性nameage,另外其具有drive()开车方法,我们规定只有年龄大于18岁才可以开车,并且默认地认为当前对象不可以开车。所以我们新建切面,来捕获对drive()方法的执行,并为其织入环绕通知:

package Test15;
public aspect DriveAspect
pointcut drivePointcut():execution(void People.drive())
&& if((thisJoinPoint.getThis() instanceof People)
&& ((People)thisJoinPoint.getThis()).getAge() > 18);
void around():drivePointcut()
System.out.println(((People)thisJoinPoint.getThis()).getName() + "可以开车...");

在切入点drivePointcut中,我们捕获了对drive()方法的执行,并且只有在当前this引用的People对象的年龄大于18的时候,我们才捕获该切入点,此时在为其织入的环绕通知中,我们改变原来程序的运行逻辑,输出可以开车

接着,新建测试类Main如下:

package Test15;
public class Main
public static void main(String[] args)
People people = new People("Gavin", 17);
people.drive();

首先,我们设置“Gavin”的年龄为17岁,这时的运行结果是:

接着,假如我们设置“Gavin”的年龄为19岁,这时的运行结果为:

两个结果与我们的预期完全一样,说明我们使用if定义的切入点完全正确。


推荐阅读
  • 本文深入探讨了Go语言中的接口型函数,通过实例分析其灵活性和强大功能,帮助开发者更好地理解和运用这一特性。 ... [详细]
  • Hanks博士是一位著名的生物技术专家,他的儿子Hankson对数学有着浓厚的兴趣。最近,Hankson遇到了一个有趣的数学问题,涉及求解特定条件下的正整数x,而不使用传统的辗转相除法。 ... [详细]
  • Android 中的布局方式之线性布局
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • Zabbix自定义监控与邮件告警配置实践
    本文详细介绍了如何在Zabbix中添加自定义监控项目,配置邮件告警功能,并解决测试告警时遇到的邮件不发送问题。 ... [详细]
  • JUnit下的测试和suite
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文通过C++语言实现了一个递归算法,用于解析并计算数学表达式的值。该算法能够处理加法、减法、乘法和除法操作。 ... [详细]
  • 尽管在WPF中工作了一段时间,但在菜单控件的样式设置上遇到了一些基础问题,特别是关于如何正确配置前景色和背景色。 ... [详细]
  • 本文深入探讨了WPF框架下的数据验证机制,包括内置验证规则的使用、自定义验证规则的实现方法、错误信息的有效展示策略以及验证时机的选择,旨在帮助开发者构建更加健壮和用户友好的应用程序。 ... [详细]
  • 本文详细探讨了在Java编程语言中,构造函数、静态代码块和构造代码块的执行顺序。首先明确了静态代码块、构造代码块以及构造函数方法体的执行优先级,随后深入分析了构造函数体执行前的具体步骤,包括父类构造器的调用、非静态变量的初始化等。 ... [详细]
  • td{border:1pxsolid#808080;}参考:和FMX相关的类(表)TFmxObjectIFreeNotification ... [详细]
  • Maven + Spring + MyBatis + MySQL 环境搭建与实例解析
    本文详细介绍如何使用MySQL数据库进行环境搭建,包括创建数据库表并插入示例数据。随后,逐步指导如何配置Maven项目,整合Spring框架与MyBatis,实现高效的数据访问。 ... [详细]
  • 使用TabActivity实现Android顶部选项卡功能
    本文介绍如何通过继承TabActivity来创建Android应用中的顶部选项卡。通过简单的步骤,您可以轻松地添加多个选项卡,并实现基本的界面切换功能。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • Beetl是一款先进的Java模板引擎,以其丰富的功能、直观的语法、卓越的性能和易于维护的特点著称。它不仅适用于高响应需求的大型网站,也适合功能复杂的CMS管理系统,提供了一种全新的模板开发体验。 ... [详细]
  • 本文将详细介绍如何使用Java编程语言生成指定数量的不重复随机数,包括具体的实现方法和代码示例。适合初学者和有一定基础的开发者参考。 ... [详细]
author-avatar
情之秋梦痕
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有